package com.dxjd.multi_camera_plugin

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.util.Log
import android.util.Size
import android.view.Surface
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.concurrent.futures.await
import kotlinx.coroutines.*
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

/**
 * 原生摄像头管理器
 *
 * 使用CameraX作为主要实现，配合Dart层面的宽高交换逻辑解决Android预览拉伸问题
 * 
 * 📋 Android预览拉伸问题的完整解决方案：
 * 
 * 🎯 问题描述：
 * Android端的相机预览在方形/圆形容器中出现严重的拉伸变形，表现为"宽度拉长、高度压缩约1/3"
 * 
 * 🔍 根本原因：
 * 1. 手机相机传感器通常是横向布局的，输出横向图像数据（如1920x1080）
 * 2. Flutter UI会自动将图像旋转90度以适应竖屏显示
 * 3. 但显示容器如果还使用原始的横向比例，就会导致宽高比不匹配，产生拉伸
 * 
 * 💡 解决策略（分为原生层 + Dart层两部分）：
 * 
 * 【原生层职责】（本文件）：
 * - 确保CameraX输出稳定、正确方向的图像流
 * - 设置合适的targetRotation，让CameraX知道我们的显示方向
 * - 提供准确的分辨率信息给Dart层
 * 
 * 【Dart层职责】（native_implementation.dart）：
 * - 获取原生层提供的分辨率信息（如width=1920, height=1080）
 * - 在创建显示容器时交换宽高（使用height作为width，width作为height）
 * - 使用FittedBox + BoxFit.cover确保正确缩放
 * 
 * 🎉 最终效果：
 * - 容器比例与UI旋转后的图像比例完全匹配
 * - 预览效果与iOS端完全一致，无任何拉伸变形
 * - 在方形、圆形、矩形等各种容器中都能正确显示
 */
class NativeCameraManager(
    private val context: Context,
    private val lifecycleOwner: LifecycleOwner,
    private val executor: ExecutorService = Executors.newSingleThreadExecutor()
) {
    private val TAG = "NativeCameraManager"
    private var cameraProviderFuture = ProcessCameraProvider.getInstance(context)
    private lateinit var cameraExecutor: ExecutorService
    private var previewView: PreviewView? = null
    private var preview: Preview? = null
    private var imageCapture: ImageCapture? = null
    var camera: Camera? = null
    private var cameraProvider: ProcessCameraProvider? = null

    private var currentLensFacing: Int = CameraSelector.LENS_FACING_BACK
    private var currentFlashMode: Int = ImageCapture.FLASH_MODE_OFF
    private var isInitialized = false
    private var callback: CameraCallback? = null
    private var targetRotation: Int = Surface.ROTATION_0
    private var isSessionPaused = false

    interface CameraCallback {
        fun onInitialized()
        fun onError(error: String)
        fun onPhotoTaken(imagePath: String, fileSize: Long)
    }

    fun setCallback(callback: CameraCallback?) {
        this.callback = callback
    }

    suspend fun initialize(lensFacing: Int, callback: CameraCallback?) = withContext(Dispatchers.Main) {
        this@NativeCameraManager.callback = callback
        cameraExecutor = executor

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            callback?.onError("缺少摄像头权限")
            return@withContext
        }

        try {
            cameraProvider = cameraProviderFuture.await()
            currentLensFacing = lensFacing
            
            // 🔧 设置默认旋转为竖屏 (ROTATION_0)
            // 
            // 这是解决Android预览拉伸问题的重要一环：
            // 
            // 📐 为什么设置为ROTATION_0：
            // - ROTATION_0 表示设备处于"自然"竖屏方向
            // - 这告诉CameraX我们的UI是竖向的，相机需要相应地调整输出
            // - 配合Dart层的宽高交换，确保整个显示流程的一致性
            // 
            // 🔄 旋转处理的作用：
            // - 让CameraX知道我们期望的显示方向
            // - 确保输出的图像流方向是稳定和可预测的
            // - 为Dart层提供正确的分辨率信息基础
            // 
            // ⚡ 动态更新：
            // - 当CameraPreviewView检测到实际的显示旋转时，会调用setTargetRotation()更新
            // - 这确保了即使设备旋转，预览效果也能保持正确
            targetRotation = Surface.ROTATION_0
            
            rebuildAndBindUseCases()
            isInitialized = true
            callback?.onInitialized()
        } catch (e: Exception) {
            Log.e(TAG, "初始化摄像头失败", e)
            callback?.onError("初始化摄像头失败: ${e.message}")
        }
    }

    private fun createUseCases() {
        Log.d(TAG, "创建 use cases，目标旋转: $targetRotation")
        
        preview = Preview.Builder()
            .setTargetRotation(targetRotation)
            .build()

        imageCapture = ImageCapture.Builder()
            .setTargetRotation(targetRotation)
            .setFlashMode(currentFlashMode)
            .build()
    }

    private fun bindUseCasesToLifecycle() {
        val cameraProvider = this.cameraProvider ?: return
        
        try {
            // 解绑所有用例
            cameraProvider.unbindAll()
            
            // 选择摄像头
            val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(currentLensFacing)
                .build()
            
            // 确保用例使用一致的配置
            Log.d(TAG, "绑定用例，旋转角度: $targetRotation")
            
            // 绑定用例到生命周期
            camera = cameraProvider.bindToLifecycle(
                lifecycleOwner,
                cameraSelector,
                preview,
                imageCapture
            )
            
            Log.d(TAG, "摄像头用例绑定成功")
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }
    
    private fun rebuildAndBindUseCases() {
        Log.d(TAG, "重新构建和绑定用例，旋转: $targetRotation")
        val cameraProvider = this.cameraProvider ?: run {
            Log.e(TAG, "CameraProvider not available, cannot rebuild use cases.")
            return
        }
        
        // 先解绑
        cameraProvider.unbindAll()
        
        // 重新构建用例
        preview = buildPreviewUseCase()
        imageCapture = buildImageCaptureUseCase()
        
        // 重新绑定
        bindUseCasesToLifecycle()
    }
    
    fun setTargetRotation(rotation: Int) {
        Log.d(TAG, "设置目标旋转: $targetRotation -> $rotation")
        if (targetRotation == rotation && isInitialized) return
        
        this.targetRotation = rotation
        
        if (isInitialized) {
            // 重新构建用例以应用新的旋转设置
            rebuildAndBindUseCases()
        }
    }

    private fun buildPreviewUseCase(): Preview {
        Log.d(TAG, "构建 Preview 用例，旋转: $targetRotation")
        return Preview.Builder()
            .setTargetRotation(targetRotation)
            .build().also { newPreview ->
                // 重新设置 surface provider
                previewView?.let { pv -> 
                    Log.d(TAG, "设置 Preview 的 SurfaceProvider")
                    newPreview.setSurfaceProvider(pv.surfaceProvider) 
                }
            }
    }

    private fun buildImageCaptureUseCase(): ImageCapture {
        Log.d(TAG, "构建 ImageCapture 用例，旋转: $targetRotation")
        return ImageCapture.Builder()
            .setTargetRotation(targetRotation)
            .setFlashMode(currentFlashMode)
            .build()
    }

    fun bindPreview(previewView: PreviewView) {
        Log.d(TAG, "绑定 PreviewView")
        this.previewView = previewView
        // 如果 preview 已经存在，立即设置 surface provider
        preview?.setSurfaceProvider(previewView.surfaceProvider)
    }

    fun getPreviewUseCase(): Preview? {
        return preview
    }

    fun getPreviewResolution(): Size? {
        return preview?.resolutionInfo?.resolution
    }

    suspend fun takePicture(outputDirectory: File) = withContext(Dispatchers.IO) {
        val imageCapture = this@NativeCameraManager.imageCapture ?: return@withContext
        val photoFile = File(outputDirectory, SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US).format(System.currentTimeMillis()) + ".jpg")
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(context),
            object : ImageCapture.OnImageSavedCallback {
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    callback?.onPhotoTaken(photoFile.absolutePath, photoFile.length())
                }
                override fun onError(exception: ImageCaptureException) {
                    Log.e(TAG, "拍照失败", exception)
                    callback?.onError("拍照失败: ${exception.message}")
                }
            }
        )
    }

    suspend fun switchCamera(targetLensFacing: Int? = null) = withContext(Dispatchers.Main) {
        if (!isInitialized) return@withContext
        
        // 如果指定了目标方向，使用指定的方向；否则在前后摄像头之间切换
        currentLensFacing = targetLensFacing 
            ?: if (currentLensFacing == CameraSelector.LENS_FACING_BACK) CameraSelector.LENS_FACING_FRONT else CameraSelector.LENS_FACING_BACK
        
        Log.d(TAG, "切换摄像头到: ${if (currentLensFacing == CameraSelector.LENS_FACING_FRONT) "前置" else "后置"}")
        rebuildAndBindUseCases()
    }
    
    fun hasFrontCamera(): Boolean = cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) ?: false
    fun hasBackCamera(): Boolean = cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
    fun hasFlash(): Boolean = camera?.cameraInfo?.hasFlashUnit() ?: false
    
    fun startPreview() {
        // Lifecycle-aware, no-op needed
    }

    fun stopPreview() {
        // Lifecycle-aware, no-op needed
    }

    fun dispose() {
        Log.d(TAG, "Disposing NativeCameraManager")
        cameraExecutor.shutdown()
        cameraProvider?.unbindAll()
        isInitialized = false
    }

    fun setFlashMode(flashMode: Int) {
        currentFlashMode = flashMode
        imageCapture?.flashMode = flashMode
        // Note: For instant effect, some might prefer rebuilding use cases
        // but that's heavier. This approach is usually sufficient.
    }

    /**
     * 暂停摄像头session
     * 在Android中，通过解绑所有用例来实现session暂停
     */
    fun pauseSession() {
        if (!isInitialized || isSessionPaused) return
        
        Log.d(TAG, "暂停摄像头session")
        try {
            cameraProvider?.unbindAll()
            isSessionPaused = true
            Log.d(TAG, "摄像头session已暂停")
        } catch (e: Exception) {
            Log.e(TAG, "暂停session失败", e)
            throw e
        }
    }

    /**
     * 恢复摄像头session
     * 在Android中，通过重新绑定用例来实现session恢复
     */
    fun resumeSession() {
        if (!isInitialized || !isSessionPaused) return
        
        Log.d(TAG, "恢复摄像头session")
        try {
            bindUseCasesToLifecycle()
            isSessionPaused = false
            Log.d(TAG, "摄像头session已恢复")
        } catch (e: Exception) {
            Log.e(TAG, "恢复session失败", e)
            throw e
        }
    }

    /**
     * 检查session是否已暂停
     */
    fun isSessionPaused(): Boolean {
        return isSessionPaused
    }
}
